#pragma once

#include <iostream>
#include <jsoncpp/json/json.h>
#include <signal.h>
#include <unistd.h>

#include "runner.hpp"
#include "compiler.hpp"

namespace ns_compile_run
{
    using namespace ns_util;
    using namespace ns_compiler;
    using namespace ns_runner;
    class Compile_run
    {
    public:
        static void RemoveFile(const std::string& file_name)
        {
            //写出路径加文件  -->  是否存在  -->  存在就用unlink删除
            std::string _src = PathUtil::Src(file_name);
            if(FileUtil::isFilexist(_src)) unlink(_src.c_str());

            std::string _exc = PathUtil::Exc(file_name);
            if(FileUtil::isFilexist(_exc)) unlink(_exc.c_str());

            std::string _compileStderr = PathUtil::CompileStderr(file_name);
            if(FileUtil::isFilexist(_compileStderr)) unlink(_compileStderr.c_str());

            std::string _stderr = PathUtil::Stderr(file_name);
            if(FileUtil::isFilexist(_stderr)) unlink(_stderr.c_str());

            std::string _stdin = PathUtil::Stdin(file_name);
            if(FileUtil::isFilexist(_stdin)) unlink(_stdin.c_str());

            std::string _stdout = PathUtil::Stdout(file_name);
            if(FileUtil::isFilexist(_stdout)) unlink(_stdout.c_str());

        }

        /*
         * 输出code对应的解释
         */
        static std::string CodetoDesc(int code, const std::string &file_name)
        {
            std::string desc;
            switch (code)
            {
            case 0:
                desc = "编译运行成功";
                break;
            case -1:
                desc = "用户传入的代码为空";
                break;
            case -2:
                desc = "未知错误";
                break;
            case -3:
                FileUtil::ReadFile(PathUtil::CompileStderr(file_name), &desc);
                break;
            case SIGABRT:
                desc = "超出内存限制";
                break;
            case SIGXCPU:
                desc = "超出运行时间限制";
                break;
            case SIGFPE:
                desc = "浮点数错误";
                break;
            default:
                desc = "未知：" + std::to_string(code);
            }
            return desc;
        }

        /**********************************
         * 使用start后编译并运行
         * 输入：
         * code 用户提交的代码
         * input 用户提交的输入，不做处理
         * cpu_limit cpu时间限制
         * as_limit 内存限制
         *
         * 输出：
         * status 状态码
         * reason 请求的结果
         * --------------------------------
         * in_json:{"code":",#include....","input":"",cpu_limit:1,as_limit:1024}
         * out_json:{"status":0,"reason":"...","stdout":"...","stderr":"..."}
         **********************************/
        static void Start(const std::string &in_json, std::string *out_json)
        {
            Json::Value jv;
            Json::Reader reader; // 读取序列化
            // 要解析     从哪解析  放到哪
            reader.parse(in_json, jv);
            // 提取
            std::string code = jv["code"].asString();
            std::string input = jv["input"].asString();
            int cpu_limit = jv["cpu_limit"].asInt();
            int as_limit = jv["as_limit"].asInt();

            // 记录错误码
            int status_code = 0;
            int run_code = 0;
            std::string file_name;

            // 差错处理
            if (code.size() == 0)
            {
                status_code = -1; // 传入空代码
                goto END;
            }

            // 获得唯一的名字
            file_name = FileUtil::UniqueName();

            // 形成临时的src文件
            // 把代码写到这个文件里
            if (!FileUtil::WriteFile(PathUtil::Src(file_name), code))
            {
                status_code = -2; // 写入错误，给用户展示为：未知错误
                goto END;
            }

            // 编译运行起来
            if (!Compiler::compile(file_name))
            {
                status_code = -3; // 编译失败了
                goto END;
            }

            // 运行完成 0
            // 程序内部错误 < 0
            // 运行不完成(抛异常) > 0
            run_code = Run::run(file_name, cpu_limit, as_limit);
            if (run_code < 0)
            {
                status_code = -2; // 内部错误
            }
            else if (run_code > 0)
            {
                status_code = run_code;
            }
            else
            {
                // 运行成功
                status_code = 0;
            }

        END:
            Json::Value out;
            Json::StyledWriter writer;
            out["status"] = status_code;
            out["reason"] = CodetoDesc(status_code, file_name);
            // 如果全部都成功了
            // 也就是也形成了stdout和stderr两个文件
            if (status_code == 0)
            {
                std::string _stdout;
                FileUtil::ReadFile(PathUtil::Stdout(file_name), &_stdout, true);
                out["stdout"] = _stdout;
                std::string _stderr;
                FileUtil::ReadFile(PathUtil::Stderr(file_name), &_stderr,true);
                out["stderr"] = _stderr;
            }
            // 写入
            *out_json = writer.write(out);

            //跑完就删除
            RemoveFile(file_name);
        }
    };
}